using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Diagnostics;

namespace IBNet
{
   /// <summary>
   /// Represents a financial instrument.
   /// </summary>
   [DebuggerDisplay("Symbol = {Symbol, nq}, LocalSymbol = {LocalSymbol}, FullSymbol = {FullSymbol}")]
   public class Contract
   {
      private readonly string symbol;
      private readonly string localSymbol;
      private readonly string fullSymbol;

      #region Constructors

      /// <summary>
      /// Creates a new Contract.
      /// </summary>
      /// <param name="symbol">The symbol.</param>
      /// <param name="securityType">The security type.</param>
      /// <param name="exchange">The exchange.</param>
      /// <param name="localSymbol">The local symbol.</param>
      /// <param name="currency">The currency.</param>
      public Contract(string symbol, SecurityType securityType, string exchange,
         string localSymbol, string currency)
         : this(0, symbol, securityType, null, 0, RightType.Undefined, null,
                exchange, currency, localSymbol, null, null, null)
      {
      }

      /// <summary>
      /// Creates a new Contract.
      /// </summary>
      /// <param name="contractId">The unique contract Id.</param>
      /// <param name="symbol">The symbol.</param>
      /// <param name="securityType">The security type.</param>
      /// <param name="expiry">The expiration date in format YYYYMM.</param>
      /// <param name="strike">The strike price.</param>
      /// <param name="rightType">The right type (Put or Call).</param>
      /// <param name="multiplier">The future or option multiplier.</param>
      /// <param name="exchange">The order destination, such as SMART.</param>
      /// <param name="currency">The currency this contract trades in.</param>
      /// <param name="localSymbol">This is the local exchange symbol of the underlying asset.</param>
      /// <param name="primaryExchange">The listing exchange for the contract (do not specify SMART).</param>
      /// <param name="comboLegsDescription">The combo legs description.</param>
      /// <param name="underlyingComponent">The underlying component.</param>
      protected Contract(int contractId, string symbol, SecurityType securityType,
         string expiry, decimal strike, RightType rightType, string multiplier,
         string exchange, string currency, string localSymbol, string primaryExchange,
         string comboLegsDescription, UnderlyingComponent underlyingComponent)
      {
         if (String.IsNullOrEmpty(symbol))
            throw new ArgumentNullException("symbol");
         
         this.ContractId = contractId;
         this.symbol = (symbol != null) ? symbol.ToUpper() : null;
         this.SecurityType = securityType;
         this.Expiry = expiry;
         this.Strike = strike;
         this.RightType = rightType;
         this.Multiplier = multiplier;
         this.Exchange = exchange;
         this.Currency = currency;
         this.PrimaryExchange = primaryExchange;
         this.ComboLegsDescription = comboLegsDescription;
         this.UnderlyingComponent = underlyingComponent;
         if (localSymbol != null)
         {
            this.localSymbol = localSymbol.ToUpper();
         }

         if (this.SecurityType == SecurityType.Cash)
         {
            this.fullSymbol = this.Symbol + "." + this.Currency;
         }
         else if (this.SecurityType == SecurityType.Future)
         {
            this.fullSymbol = this.LocalSymbol;
         }
         else if (this.SecurityType == SecurityType.Stock)
         {
            this.fullSymbol = this.Symbol;
         }
      }

      #endregion // Constructors

      #region Properties

      /// <summary>
      /// Gets the symbol of the underlying asset.
      /// </summary>
      public string Symbol { get { return symbol; } }

      /// <summary>
      /// Gets the full symbol for this contract. This field holds, for example,
      /// "EUR.USD" whereas Symbol holds "EUR" and Currency holds "USD".
      /// </summary>
      public string FullSymbol { get { return fullSymbol; } }

      /// <summary>
      /// Gets or sets the security type.
      /// </summary>
      public SecurityType SecurityType { get; set; }

      /// <summary>
      /// Gets or sets the exchange the order is sent to, such as SMART.
      /// </summary>
      public string Exchange { get; set; }

      /// <summary>
      /// Gets or sets the currency the underlying trades in. 
      /// For Forex pairs such as EUR/USD, Symbol is "EUR" and Currency is "USD".
      /// </summary>
      /// <remarks>
      /// Ambiguities may require that this field be specified.
      /// For example, IBM can trade in GBP or USD when SMART is the exchange.
      /// </remarks>
      public string Currency { get; set; }

      /// <summary>
      /// Gets or sets the option strike price.
      /// </summary>
      public decimal Strike { get; set; }

      /// <summary>
      /// Gets or sets the right type (Put or Call).
      /// </summary>
      public RightType RightType { get; set; }

      /// <summary>
      /// Gets or sets the combo legs description.
      /// </summary>
      public string ComboLegsDescription { get; set; }

      /// <summary>
      /// Gets or sets the unique contract Id.
      /// </summary>
      public int ContractId { get; set; }

      /// <summary>
      /// Gets or sets the primary exchange the underlying trades on.
      /// </summary>
      public string PrimaryExchange { get; set; }

      /// <summary>
      /// Gets or sets the combo legs.
      /// </summary> 
      public Collection<ComboLeg> ComboLegs { get; set; }

      /// <summary>
      /// Gets or sets a value indicating whether historical data requests can be performed for 
      /// expired futures contracts. Historical data requests on expired contracts are limited to the
      /// last year of the contract's life.
      /// </summary>
      public bool DoesIncludeExpired { get; set; }

      /// <summary>
      /// Gets or sets the local exchange symbol of the underlying asset.
      /// </summary>
      public string LocalSymbol { get { return localSymbol; } }

      /// <summary>
      /// Gets or sets the underlying component.
      /// </summary>
      public UnderlyingComponent UnderlyingComponent { get; set; }

      /// <summary>
      /// Gets or sets the expiration date. Use format YYYYMM.
      /// </summary>
      public string Expiry { get; set; }

      /// <summary>
      /// Gets or sets the future or option contract multiplier.
      /// </summary>
      public string Multiplier { get; set; }

      #endregion // Properties
   }
}